﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Globalization;
using System.Threading;

namespace GTA
{
    public partial class FrmDisponibilidadeArquitetos : BaseForm
    {
        #region Local Enumerations
        private enum GridStyle
        {
            Future,
            InProgress,
            Overdue,
            Holiday,
            WeekEnd
        }
        #endregion

        #region Local Objects
        List<BusinessEntity.ArchitectDisponibility> listDisponibility = null;
        #endregion

        #region Starting Form
        public FrmDisponibilidadeArquitetos()
        {
            InitializeComponent();
        }
        private void FrmDisponibilidadeArquitetos_Load(object sender, EventArgs e)
        {
            StartForm();
        }
        private void StartForm()
        {
            try
            {
                LoadSheetCalendarDays();
                RestoreSearchFilter();
            }
            catch (Exception ex)
            {
                HandleException("Inicialização da tela", ex);
            }
        }
        #endregion

        #region Events
        private void cmdSearch_Click(object sender, EventArgs e)
        {
            SearchDisponibility();
        }
        private void cmdCleanFilter_Click(object sender, EventArgs e)
        {
            CleanFilter();
        }
        private void gridSheet_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            OpenTasksDetails();
        }
        private void cmdDetails_Click(object sender, EventArgs e)
        {
            OpenTasksDetails();
        }
        private void detalhesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenTasksDetails();
        }
        private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
        {
            ValidateEnableContextMenuTasksDetails();
        }
        private void gridSheet_SelectionChanged(object sender, EventArgs e)
        {
            HandleSheetSelection();
        }
        #endregion

        #region Methods
        private void CleanFilter()
        {
            try
            {
                ucSearchFilter.CleanFilter();
                SaveFilter();
            }
            catch (Exception ex)
            {
                HandleException("Limpar o filtro de pesquisa", ex);
            }
        }
        private void SearchDisponibility()
        {
            try
            {
                Cursor = Cursors.WaitCursor;
                BusinessLogic.GTA bl = new BusinessLogic.GTA();
                listDisponibility = bl.ListArchitectDisponibility(GetSearchFilter(), Program.LoggedUser);
                BindDisponibilitySheet(listDisponibility);
                SaveFilter();
            }
            catch (Exception ex)
            {
                HandleException("Pesquiar disponibilidade de arquitetos", ex);
            }
            finally
            {
                Cursor = Cursors.Default;
            }
        }
        private BusinessEntity.TaskFilter GetSearchFilter()
        {
            BusinessEntity.TaskFilter filter = new GTA.BusinessEntity.TaskFilter();
            filter.Project = ucSearchFilter.GetSelectedProjects();
            filter.DesignedTo = ucSearchFilter.GetSelectedResponsibles();
            return filter;
        }
        private void BindDisponibilitySheet(List<BusinessEntity.ArchitectDisponibility> disponibility)
        {
            gridSheet.Rows.Clear();

            if (disponibility != null && disponibility.Count > 0)
            {
                //Efetua a leitura de cada Arquiteto
                foreach (BusinessEntity.ArchitectDisponibility itemDisponibility in disponibility)
                {
                    //Cria a linha que representa o plano de disponibilidade do arquiteto.
                    gridSheet.Rows.Add();
                    gridSheet.Rows[gridSheet.Rows.Count - 1].HeaderCell.Value = itemDisponibility.Architect.Name;

                    //Obtem as tasks do arquiteto atrasadas em comparação com a primeira data da grade.
                    DateTime firstSheetDate = DateTime.MinValue;
                    DateTime.TryParseExact(gridSheet.Columns[0].HeaderText, "dd/MM", DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, out firstSheetDate);
                    List<BusinessEntity.Task> tasksOverdue = itemDisponibility.Tasks.FindAll(itemTask =>
                        itemTask.State.Description.ToLowerInvariant().CompareTo("finalizado") != 0 &&
                        itemTask.State.Description.ToLowerInvariant().CompareTo("cancelado") != 0 &&
                        firstSheetDate.Date.CompareTo(itemTask.ScheduleEstimatedEnd) > 0);
                    if (tasksOverdue != null && tasksOverdue.Count > 0)
                    {
                        StringBuilder descriptionOverdue = new StringBuilder("Tasks Atrasadas:\r\n");
                        foreach (BusinessEntity.Task itemOverdue in tasksOverdue)
                            AppendTaskDetailDescription(descriptionOverdue, itemOverdue);
                        gridSheet.Rows[gridSheet.Rows.Count - 1].HeaderCell.ToolTipText = descriptionOverdue.ToString();
                        gridSheet.Rows[gridSheet.Rows.Count - 1].HeaderCell.Style.ForeColor = Color.FromArgb(192, 0, 0); //Color.Red;
                    }


                    //Efetua a varredura das datas existentes na grade para obter as tasks do arquiteto
                    for (Int32 i = 0; i < gridSheet.Columns.Count; i++)
                    {
                        DateTime date = DateTime.MinValue;
                        DateTime.TryParseExact(gridSheet.Columns[i].HeaderText, "dd/MM", DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, out date);

                        bool includeTask = true;

                        if (itemDisponibility.Architect.UserAdditionalDays != null &&
                            itemDisponibility.Architect.UserAdditionalDays.Count > 0 &&
                            itemDisponibility.Architect.UserAdditionalDays.Exists(it => it.Date.Date.CompareTo(date.Date) == 0))
                            includeTask = true;
                        else
                        {
                            if (itemDisponibility.Architect.UserAbsences != null &&
                                itemDisponibility.Architect.UserAbsences.Count > 0 &&
                                itemDisponibility.Architect.UserAbsences.Exists(it =>
                                    date.Date.CompareTo(it.StartDate.Date) >= 0 &&
                                    date.Date.CompareTo(it.EndDate.Date) <= 0))
                            {
                                BusinessEntity.UserManagement.UserAbsences absence = itemDisponibility.Architect.UserAbsences.Find(it => date.Date.CompareTo(it.StartDate.Date) >= 0 &&
                                                                                                                          date.Date.CompareTo(it.EndDate.Date) <= 0);
                                bool addAbsence = true;
                                if (!absence.WeekEnd && (date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday))
                                    addAbsence = false;
                                if (addAbsence)
                                    gridSheet.Rows[gridSheet.Rows.Count - 1].Cells[i].Value = "Folga";
                                includeTask = false;
                            }
                            else if (date.DayOfWeek == DayOfWeek.Saturday ||
                                     date.DayOfWeek == DayOfWeek.Sunday ||
                                    (Program.Holidays != null &&
                                     Program.Holidays.Holiday != null &&
                                     Program.Holidays.Holiday.Exists(itemHoliday => itemHoliday.Date.CompareTo(date.Date) == 0)))
                                includeTask = false;
                        }

                        if (includeTask)
                        {
                            //Obtem as tasks do arquiteto referente a esta data.
                            List<BusinessEntity.Task> tasksDate = itemDisponibility.Tasks.FindAll(itemTask =>
                                date.Date.CompareTo(itemTask.ScheduleEstimatedStart.Date) >= 0 &&
                                (
                                    (itemTask.ScheduleRealizedEnd != DateTime.MinValue &&
                                    date.Date.CompareTo(itemTask.ScheduleRealizedEnd.Date) <= 0)
                                    ||
                                    (itemTask.ScheduleRealizedEnd == DateTime.MinValue &&
                                    date.Date.CompareTo(itemTask.ScheduleEstimatedEnd.Date) <= 0)
                                ));

                            if (tasksDate != null && tasksDate.Count > 0)
                            {
                                //Existindo tasks na data, efetua a inclusão dos códigos e tratamento do status.
                                StringBuilder taskDateDescription = new StringBuilder();
                                StringBuilder taskDateFullDescription = new StringBuilder();
                                foreach (BusinessEntity.Task itemTaskDate in tasksDate)
                                {
                                    taskDateDescription.Append(itemTaskDate.ID.ToString());
                                    taskDateDescription.Append(" - ");
                                    AppendTaskDetailDescription(taskDateFullDescription, itemTaskDate);
                                }
                                taskDateDescription.Remove(taskDateDescription.Length - 2, 2);
                                gridSheet.Rows[gridSheet.Rows.Count - 1].Cells[i].Value = taskDateDescription.ToString();
                                gridSheet.Rows[gridSheet.Rows.Count - 1].Cells[i].ToolTipText = taskDateFullDescription.ToString();

                                SetSheetCellStyle(GridStyle.InProgress, gridSheet.Rows[gridSheet.Rows.Count - 1].Cells[i]);
                            }
                            else
                                //Não existindo task na data, marca a data como disponível.
                                SetSheetCellStyle(GridStyle.Future, gridSheet.Rows[gridSheet.Rows.Count - 1].Cells[i]);
                        }
                    }
                }
                LoadSheetUnusedDays();
            }
        }
        private void AppendTaskDetailDescription(StringBuilder stringBuilder, GTA.BusinessEntity.Task task)
        {
            stringBuilder.Append(task.ID.ToString());
            stringBuilder.Append(" - ");
            stringBuilder.Append(task.Title);
            stringBuilder.Append(" - ");
            stringBuilder.Append(task.ScheduleEstimatedStart.ToString("dd/MM/yyyy"));
            stringBuilder.Append(" - ");
            stringBuilder.Append(task.ScheduleEstimatedEnd.ToString("dd/MM/yyyy"));
            stringBuilder.Append("\r\n");
        }
        private void LoadSheetUnusedDays()
        {
            for (Int32 i = 0; i < gridSheet.Columns.Count; i++)
            {
                DateTime date = DateTime.MinValue;
                DateTime.TryParseExact(gridSheet.Columns[i].HeaderText, "dd/MM", DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, out date);

                if (date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday)
                {
                    foreach (DataGridViewRow row in gridSheet.Rows)
                        SetSheetCellStyle(GridStyle.WeekEnd, row.Cells[i]);
                }

                if (Program.Holidays != null &&
                Program.Holidays.Holiday != null &&
                Program.Holidays.Holiday.Count > 0)
                {
                    if (Program.Holidays.Holiday.Find(itemDate => itemDate.Date.CompareTo(date.Date) == 0) != DateTime.MinValue)
                    {
                        foreach (DataGridViewRow row in gridSheet.Rows)
                            SetSheetCellStyle(GridStyle.Holiday, row.Cells[i]);
                    }
                }
            }
        }
        private void SetSheetCellStyle(GridStyle style, DataGridViewCell cell)
        {
            switch (style)
            {
                case GridStyle.Future:
                    cell.Style.BackColor = Color.LightGreen;
                    break;
                case GridStyle.InProgress:
                    cell.Style.BackColor = Color.LightYellow;
                    break;
                case GridStyle.Overdue:
                    cell.Style.BackColor = Color.LightSalmon;
                    break;
                case GridStyle.Holiday:
                    //cell.Style.BackColor = Color.LightGray;
                    cell.Style.BackColor = Color.FromArgb(255, 192, 128);
                    break;
                case GridStyle.WeekEnd:
                    cell.Style.BackColor = Color.LightBlue;
                    break;
                default:
                    break;
            }
        }
        private void LoadSheetCalendarDays()
        {
            try
            {
                for (Int32 i = 0; i < 30; i++)
                {
                    gridSheet.Columns.Add("lbSheetHeader" + DateTime.Now.AddDays(i).ToString("ddMM"), DateTime.Now.AddDays(i).ToString("dd/MM"));
                    gridSheet.Columns[gridSheet.Columns.Count - 1].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
                    if (DateTime.Now.AddDays(i).DayOfWeek == DayOfWeek.Saturday ||
                        DateTime.Now.AddDays(i).DayOfWeek == DayOfWeek.Sunday)
                        gridSheet.Columns[gridSheet.Columns.Count - 1].HeaderCell.Style.BackColor = Color.LightBlue;
                }
            }
            catch (Exception ex)
            {
                HandleException("Carregar o padrão da grade de disponibilidade", ex);
            }
        }
        private void OpenTasksDetails()
        {
            try
            {
                if (gridSheet.SelectedCells.Count == 1
                && gridSheet.SelectedCells[0].Value != null
                && !String.IsNullOrEmpty(gridSheet.SelectedCells[0].Value.ToString()))
                {
                    String[] tasksIDs = gridSheet.SelectedCells[0].Value.ToString().Split('-');
                    if (tasksIDs.Length > 0)
                    {
                        List<BusinessEntity.Task> tasks = new List<GTA.BusinessEntity.Task>();
                        foreach (String itemID in tasksIDs)
                        {
                            BusinessEntity.ArchitectDisponibility architect = listDisponibility.Find(it =>
                                it.Tasks.Find(tsk => tsk.ID.CompareTo(Convert.ToInt32(itemID.Trim())) == 0) != null);
                            tasks.Add(architect.Tasks.Find(tsk => tsk.ID.CompareTo(Convert.ToInt32(itemID.Trim())) == 0));
                        }
                        FrmTaskDetails wd = new FrmTaskDetails(tasks);
                        wd.ShowInTaskbar = false;
                        wd.ShowDialog(this);
                    }
                }
            }
            catch (Exception ex)
            {
                HandleException("Abrir detalhes das tasks selecionadas", ex);
            }
        }
        private void ValidateEnableContextMenuTasksDetails()
        {
            ctxTasksDetails.Enabled = gridSheet.SelectedCells.Count == 1
                && gridSheet.SelectedCells[0].Value != null
                && !String.IsNullOrEmpty(gridSheet.SelectedCells[0].Value.ToString());
        }
        private void HandleSheetSelection()
        {
            cmdDetails.Enabled = gridSheet.SelectedCells.Count == 1
                && gridSheet.SelectedCells[0].Value != null
                && !String.IsNullOrEmpty(gridSheet.SelectedCells[0].Value.ToString());
        }
        private void SaveFilter()
        {
            try
            {
                BusinessEntity.TaskFilter filter = GetSearchFilter();
                Program.SystemConfiguration.FilterSearchFrmDisponibilidadeArquitetos = new GTA.BusinessEntity.Configuration.SearchFilter(filter);
                Program.SaveSystemConfiguration();
            }
            catch (Exception ex)
            {
                HandleException("Salvar o filtro da pesquisa.", ex);
            }
        }
        private void RestoreSearchFilter()
        {
            try
            {
                if (Program.SystemConfiguration.FilterSearchFrmDisponibilidadeArquitetos != null)
                {
                    ucSearchFilter.RestoreSearchFilterProjects(Program.SystemConfiguration.FilterSearchFrmDisponibilidadeArquitetos.Project);
                    ucSearchFilter.RestoreSearchFilterResponsibles(Program.SystemConfiguration.FilterSearchFrmDisponibilidadeArquitetos.DesignedTo);
                }
            }
            catch (Exception ex)
            {
                HandleException("Restaurar os últimos filtros utilizados.", ex);
            }
        }
        #endregion
    }
}
